package process

import (
	"encoding/json"
	"errors"
	"fmt"
	"go_chat_system/client/model"
	"go_chat_system/client/utils"
	"go_chat_system/common"
	"go_chat_system/common/entity"
	"net"
	"reflect"
	"strconv"
)

type AccountProcess struct {
}

var (
	account entity.Account
	reply   common.MessageReply
)

//region 登录
// 登录界面
func (this *AccountProcess) LoginPage() {
	fmt.Println("\n------------------------ 登录聊天系统 ------------------------")
	fmt.Printf("请输入用户编号:")
	fmt.Scanln(&account.UserId)
	fmt.Printf("请输入用户密码:")
	fmt.Scanln(&account.Password)
	err := login(account.UserId, account.Password)
	if err == nil {
		fmt.Println("登录成功！")
	} else {
		fmt.Println("登录失败，原因：", err)
	}
}

func login(userId int, password string) (err error) {

	loginMess := entity.Account{
		UserId:   userId,
		Password: password,
	}
	data, err := toJsonMessage(common.Login, loginMess)
	err = sendData(data)
	return
}

// 登录处理
func loginReply(conn net.Conn, mess common.Message) (err error) {
	err = json.Unmarshal([]byte(mess.Data), &reply)
	if reply.Code == 255 {
		//fmt.Println("登录成功！")
		// 初始化CurrentUser
		currentUser = model.CurrentUser{
			Account: getCurrentUserByOnlineUser(account.UserId, reply.Result),
			Conn:    conn,
		}
		// 获取所有已经在线的用户列表
		addBeenOnlineUser(reply.Result)
		// 显示当前在线用户
		outputOnlineUser()
		// 启动一个与服务器保持通讯的协程，并推送信息
		createSafeGo(processServerMessage, conn, func(err interface{}) {
			fmt.Println("协程异常！")
		})
		// 登陆成功后的菜单
		for {
			showHomeMenu()
		}
	} else if reply.Code == 404 {
		fmt.Println("用户不存在，请先注册！")
	} else {
		err = errors.New(reply.Error)
	}
	return
}

// 获取所有已经在线的用户列表
func addBeenOnlineUser(result interface{}) {
	users, is := result.(map[string]interface{})
	if is {
		for id, val := range users {
			var user entity.Account
			reflectObject(val, &user)
			id, err := strconv.Atoi(id)
			if err != nil {
				continue
			}
			onlineUsers[id] = &user
			fmt.Printf("addBeenOnlineUser Value:%v,Type:%T\n", user, user)
		}
	}
}

// 获取当前用户信息
func getCurrentUserByOnlineUser(userId int, result interface{}) (user entity.Account) {
	users, is := result.(map[string]interface{})
	//fmt.Printf("Reslut is:%t Value:%v,Type:%T\n", is, result, result)
	if is {
		for id, val := range users {
			//fmt.Printf("User Id:%v Value:%v ValueType:%T\n", id, val, val)
			//v, is := val.(map[string]interface{})
			//fmt.Printf("Value is:%t Value:%v,Type:%T\n", is, v, v)

			reflectObject(val, &user)
			if strconv.Itoa(userId) == id {
				fmt.Printf("getCurrentUserByOnlineUser Value:%v,Type:%T\n", user, user)
				return
			}
		}
	}
	return
}

// 泛型转对象
func reflectObject(val interface{}, i interface{}) {
	refType := reflect.TypeOf(i)
	refValue := reflect.ValueOf(i)
	if refValue.Kind() != reflect.Ptr && refValue.Elem().Kind() == reflect.Struct {
		fmt.Println("Expect Struct!")
		return
	}
	// 和之前的操作相比，都加上了Elem()
	for i := 0; i < refValue.Elem().NumField(); i++ {
		tagValue := refType.Elem().Field(i).Tag.Get("json")
		arr, is := val.(map[string]interface{})
		if is {
			for k, v := range arr {
				if tagValue == k {
					field := refValue.Elem().Field(i)
					//fmt.Printf("field:%v Type:%v Value:%v Type:%T\n", tagValue, field.Type().String(), v, v)
					switch field.Type().String() {
					case "string":
						field.SetString(v.(string))
					case "int":
						field.SetInt(int64(v.(float64)))
					}
				}
			}
		}
	}
}

//endregion

//region 注册
// 注册界面
func (this *AccountProcess) RegisterPage() {
	fmt.Println("\n--------------------------- 注册聊天用户 ---------------------------")
	fmt.Printf("请输入用户编号:")
	fmt.Scanln(&account.UserId)
	fmt.Printf("请输入用 户 名:")
	fmt.Scanln(&account.UserName)
	fmt.Printf("请输入用户密码:")
	fmt.Scanln(&account.Password)
	err := register(account)
	if err == nil {
		fmt.Println("注册成功！")
		this.LoginPage()
	} else {
		fmt.Println("注册失败，原因：", err)
	}
}

// 注册
func register(registerMes entity.Account) (err error) {
	data, err := toJsonMessage(common.Register, registerMes)
	return sendData(data)
}

// 注册返回处理
func registerRely(conn net.Conn, mess common.Message) (err error) {
	err = json.Unmarshal([]byte(mess.Data), &reply)
	if reply.Code != 255 {
		err = errors.New(reply.Error)
	}
	return
}

//endregion

//region 发送/接收公共函数
// 序列化消息结构体
func toJsonMessage(t string, i interface{}) (mess []byte, err error) {
	// 序列化消息的内容
	d, err := json.Marshal(i)
	if err != nil {
		return
	}
	// 发送消息的长度
	message := common.Message{
		Type: t,
		Data: string(d),
	}
	// 序列化消息结构体
	mess, err = json.Marshal(message)
	if err != nil {
		fmt.Println("Json Marshal Message Error:", err)
		return
	}
	return
}

// 向服务器发送消息
func sendData(data []byte) (err error) {
	// 连接服务器
	conn, err := net.Dial("tcp", "192.168.2.99:8888")
	if err != nil {
		return
	}
	defer conn.Close()
	transfer := &utils.Transfer{
		Conn: conn,
	}
	// 发送消息
	transfer.WriteData(data)
	// 接收消息
	mess, err := transfer.ReadData()
	err = clientMessage(conn, mess)
	return
}

// 根据Message.Type调用不同的函数
func clientMessage(conn net.Conn, mess common.Message) (err error) {
	switch mess.Type {
	case common.LoginReply:
		err = loginReply(conn, mess) // 登录处理
	case common.RegisterReply:
		err = registerRely(conn, mess) // 注册处理
	default:
		fmt.Println("未知返回：", mess.Type)
	}
	return
}

//endregion
